﻿// *********************************************************************
// Copyright (c) Microsoft Corporation.  All rights reserved.
// Licensed under the MIT License
// *********************************************************************

using System;
using System.Linq.Expressions;
using Microsoft.StreamProcessing.Aggregates;
using Microsoft.StreamProcessing.Internal;

namespace Microsoft.StreamProcessing
{
    public static partial class Streamable
    {
        /// <summary>
        /// Groups input events by a key selector and applies an aggregate on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        public static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>> aggregate1,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(merger, nameof(merger));

            if (typeof(TOuterKey) == typeof(Empty) && source.Properties.IsStartEdgeOnly && Config.MapArity == 1)
            {
                var emptySource = (IStreamable<Empty, TInput>)source;
                var emptyAggregate1 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>>)aggregate1;
                var inlinedMerger = GroupInputInliner<TInnerKey, TOutput1, TOutput>.Transform(merger);

                return (IStreamable<TOuterKey, TOutput>)(object)new GroupedWindowStreamable<TInnerKey, TInput, TState1, TOutput1, TOutput>
                    (emptySource, emptyAggregate1(new Window<CompoundGroupKey<Empty, TInnerKey>, TInput>(emptySource.Properties.GroupNested(keySelector))), keySelector, inlinedMerger);
            }

            return source.Map(keySelector).Reduce(s => s.Aggregate(aggregate1), merger);
        }

        /// <summary>
        /// Groups input events by a key selector and applies an aggregate on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A concrete reference to an aggregate operator.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        internal static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            IAggregate<TInput, TState1, TOutput1> aggregate1,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(merger, nameof(merger));

            return source.Map(keySelector).Reduce(s => s.Aggregate(aggregate1), merger);
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate2">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        public static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>> aggregate1,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>> aggregate2,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, StructTuple<TOutput1, TOutput2>>> aggregateMerger =
                (output1, output2) => new StructTuple<TOutput1, TOutput2> {
                    Item1 = output1,
                    Item2 = output2
                };

            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2);

            if (typeof(TOuterKey) == typeof(Empty) && source.Properties.IsStartEdgeOnly && Config.MapArity == 1)
            {
                var emptySource = (IStreamable<Empty, TInput>)source;
                var emptyAggregate1 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>>)aggregate1;
                var emptyAggregate2 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>>)aggregate2;

                var window = new Window<CompoundGroupKey<Empty, TInnerKey>, TInput>(emptySource.Properties.GroupNested(keySelector));
                var agg1 = emptyAggregate1(window);
                var agg2 = emptyAggregate2(window);
                var compound = AggregateFunctions.Combine(agg1, agg2, aggregateMerger);

                return (IStreamable<TOuterKey, TOutput>)(object)new GroupedWindowStreamable<TInnerKey, TInput, StructTuple<TState1, TState2>, StructTuple<TOutput1, TOutput2>, TOutput>
                        (emptySource, compound, keySelector, GroupInputInliner<TInnerKey, StructTuple<TOutput1, TOutput2>, TOutput>.Transform(reducerTemplate.InlineCalls()));
            }

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate2">A concrete reference to an aggregate operator.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        internal static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            IAggregate<TInput, TState1, TOutput1> aggregate1,
            IAggregate<TInput, TState2, TOutput2> aggregate2,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, StructTuple<TOutput1, TOutput2>>> aggregateMerger =
                (output1, output2) => new StructTuple<TOutput1, TOutput2> {
                    Item1 = output1,
                    Item2 = output2
                };
            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2);

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate2">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate3">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        public static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>> aggregate1,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>> aggregate2,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>> aggregate3,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, StructTuple<TOutput1, TOutput2, TOutput3>>> aggregateMerger =
                (output1, output2, output3) => new StructTuple<TOutput1, TOutput2, TOutput3> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3
                };

            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3);

            if (typeof(TOuterKey) == typeof(Empty) && source.Properties.IsStartEdgeOnly && Config.MapArity == 1)
            {
                var emptySource = (IStreamable<Empty, TInput>)source;
                var emptyAggregate1 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>>)aggregate1;
                var emptyAggregate2 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>>)aggregate2;
                var emptyAggregate3 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>>)aggregate3;

                var window = new Window<CompoundGroupKey<Empty, TInnerKey>, TInput>(emptySource.Properties.GroupNested(keySelector));
                var agg1 = emptyAggregate1(window);
                var agg2 = emptyAggregate2(window);
                var agg3 = emptyAggregate3(window);
                var compound = AggregateFunctions.Combine(agg1, agg2, agg3, aggregateMerger);

                return (IStreamable<TOuterKey, TOutput>)(object)new GroupedWindowStreamable<TInnerKey, TInput, StructTuple<TState1, TState2, TState3>, StructTuple<TOutput1, TOutput2, TOutput3>, TOutput>
                        (emptySource, compound, keySelector, GroupInputInliner<TInnerKey, StructTuple<TOutput1, TOutput2, TOutput3>, TOutput>.Transform(reducerTemplate.InlineCalls()));
            }

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate2">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate3">A concrete reference to an aggregate operator.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        internal static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            IAggregate<TInput, TState1, TOutput1> aggregate1,
            IAggregate<TInput, TState2, TOutput2> aggregate2,
            IAggregate<TInput, TState3, TOutput3> aggregate3,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, StructTuple<TOutput1, TOutput2, TOutput3>>> aggregateMerger =
                (output1, output2, output3) => new StructTuple<TOutput1, TOutput2, TOutput3> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3
                };
            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3);

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate2">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate3">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate4">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        public static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>> aggregate1,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>> aggregate2,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>> aggregate3,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>> aggregate4,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4>>> aggregateMerger =
                (output1, output2, output3, output4) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4
                };

            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4);

            if (typeof(TOuterKey) == typeof(Empty) && source.Properties.IsStartEdgeOnly && Config.MapArity == 1)
            {
                var emptySource = (IStreamable<Empty, TInput>)source;
                var emptyAggregate1 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>>)aggregate1;
                var emptyAggregate2 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>>)aggregate2;
                var emptyAggregate3 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>>)aggregate3;
                var emptyAggregate4 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>>)aggregate4;

                var window = new Window<CompoundGroupKey<Empty, TInnerKey>, TInput>(emptySource.Properties.GroupNested(keySelector));
                var agg1 = emptyAggregate1(window);
                var agg2 = emptyAggregate2(window);
                var agg3 = emptyAggregate3(window);
                var agg4 = emptyAggregate4(window);
                var compound = AggregateFunctions.Combine(agg1, agg2, agg3, agg4, aggregateMerger);

                return (IStreamable<TOuterKey, TOutput>)(object)new GroupedWindowStreamable<TInnerKey, TInput, StructTuple<TState1, TState2, TState3, TState4>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4>, TOutput>
                        (emptySource, compound, keySelector, GroupInputInliner<TInnerKey, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4>, TOutput>.Transform(reducerTemplate.InlineCalls()));
            }

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate2">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate3">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate4">A concrete reference to an aggregate operator.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        internal static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            IAggregate<TInput, TState1, TOutput1> aggregate1,
            IAggregate<TInput, TState2, TOutput2> aggregate2,
            IAggregate<TInput, TState3, TOutput3> aggregate3,
            IAggregate<TInput, TState4, TOutput4> aggregate4,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4>>> aggregateMerger =
                (output1, output2, output3, output4) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4
                };
            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4);

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate2">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate3">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate4">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate5">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        public static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>> aggregate1,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>> aggregate2,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>> aggregate3,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>> aggregate4,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>> aggregate5,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5>>> aggregateMerger =
                (output1, output2, output3, output4, output5) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5
                };

            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5);

            if (typeof(TOuterKey) == typeof(Empty) && source.Properties.IsStartEdgeOnly && Config.MapArity == 1)
            {
                var emptySource = (IStreamable<Empty, TInput>)source;
                var emptyAggregate1 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>>)aggregate1;
                var emptyAggregate2 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>>)aggregate2;
                var emptyAggregate3 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>>)aggregate3;
                var emptyAggregate4 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>>)aggregate4;
                var emptyAggregate5 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>>)aggregate5;

                var window = new Window<CompoundGroupKey<Empty, TInnerKey>, TInput>(emptySource.Properties.GroupNested(keySelector));
                var agg1 = emptyAggregate1(window);
                var agg2 = emptyAggregate2(window);
                var agg3 = emptyAggregate3(window);
                var agg4 = emptyAggregate4(window);
                var agg5 = emptyAggregate5(window);
                var compound = AggregateFunctions.Combine(agg1, agg2, agg3, agg4, agg5, aggregateMerger);

                return (IStreamable<TOuterKey, TOutput>)(object)new GroupedWindowStreamable<TInnerKey, TInput, StructTuple<TState1, TState2, TState3, TState4, TState5>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5>, TOutput>
                        (emptySource, compound, keySelector, GroupInputInliner<TInnerKey, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5>, TOutput>.Transform(reducerTemplate.InlineCalls()));
            }

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate2">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate3">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate4">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate5">A concrete reference to an aggregate operator.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        internal static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            IAggregate<TInput, TState1, TOutput1> aggregate1,
            IAggregate<TInput, TState2, TOutput2> aggregate2,
            IAggregate<TInput, TState3, TOutput3> aggregate3,
            IAggregate<TInput, TState4, TOutput4> aggregate4,
            IAggregate<TInput, TState5, TOutput5> aggregate5,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5>>> aggregateMerger =
                (output1, output2, output3, output4, output5) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5
                };
            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5);

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate2">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate3">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate4">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate5">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate6">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        public static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>> aggregate1,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>> aggregate2,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>> aggregate3,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>> aggregate4,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>> aggregate5,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>> aggregate6,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6
                };

            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6);

            if (typeof(TOuterKey) == typeof(Empty) && source.Properties.IsStartEdgeOnly && Config.MapArity == 1)
            {
                var emptySource = (IStreamable<Empty, TInput>)source;
                var emptyAggregate1 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>>)aggregate1;
                var emptyAggregate2 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>>)aggregate2;
                var emptyAggregate3 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>>)aggregate3;
                var emptyAggregate4 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>>)aggregate4;
                var emptyAggregate5 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>>)aggregate5;
                var emptyAggregate6 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>>)aggregate6;

                var window = new Window<CompoundGroupKey<Empty, TInnerKey>, TInput>(emptySource.Properties.GroupNested(keySelector));
                var agg1 = emptyAggregate1(window);
                var agg2 = emptyAggregate2(window);
                var agg3 = emptyAggregate3(window);
                var agg4 = emptyAggregate4(window);
                var agg5 = emptyAggregate5(window);
                var agg6 = emptyAggregate6(window);
                var compound = AggregateFunctions.Combine(agg1, agg2, agg3, agg4, agg5, agg6, aggregateMerger);

                return (IStreamable<TOuterKey, TOutput>)(object)new GroupedWindowStreamable<TInnerKey, TInput, StructTuple<TState1, TState2, TState3, TState4, TState5, TState6>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6>, TOutput>
                        (emptySource, compound, keySelector, GroupInputInliner<TInnerKey, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6>, TOutput>.Transform(reducerTemplate.InlineCalls()));
            }

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate2">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate3">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate4">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate5">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate6">A concrete reference to an aggregate operator.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        internal static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            IAggregate<TInput, TState1, TOutput1> aggregate1,
            IAggregate<TInput, TState2, TOutput2> aggregate2,
            IAggregate<TInput, TState3, TOutput3> aggregate3,
            IAggregate<TInput, TState4, TOutput4> aggregate4,
            IAggregate<TInput, TState5, TOutput5> aggregate5,
            IAggregate<TInput, TState6, TOutput6> aggregate6,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6
                };
            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6);

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate2">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate3">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate4">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate5">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate6">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate7">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        public static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>> aggregate1,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>> aggregate2,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>> aggregate3,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>> aggregate4,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>> aggregate5,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>> aggregate6,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>> aggregate7,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7
                };

            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7);

            if (typeof(TOuterKey) == typeof(Empty) && source.Properties.IsStartEdgeOnly && Config.MapArity == 1)
            {
                var emptySource = (IStreamable<Empty, TInput>)source;
                var emptyAggregate1 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>>)aggregate1;
                var emptyAggregate2 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>>)aggregate2;
                var emptyAggregate3 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>>)aggregate3;
                var emptyAggregate4 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>>)aggregate4;
                var emptyAggregate5 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>>)aggregate5;
                var emptyAggregate6 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>>)aggregate6;
                var emptyAggregate7 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>>)aggregate7;

                var window = new Window<CompoundGroupKey<Empty, TInnerKey>, TInput>(emptySource.Properties.GroupNested(keySelector));
                var agg1 = emptyAggregate1(window);
                var agg2 = emptyAggregate2(window);
                var agg3 = emptyAggregate3(window);
                var agg4 = emptyAggregate4(window);
                var agg5 = emptyAggregate5(window);
                var agg6 = emptyAggregate6(window);
                var agg7 = emptyAggregate7(window);
                var compound = AggregateFunctions.Combine(agg1, agg2, agg3, agg4, agg5, agg6, agg7, aggregateMerger);

                return (IStreamable<TOuterKey, TOutput>)(object)new GroupedWindowStreamable<TInnerKey, TInput, StructTuple<TState1, TState2, TState3, TState4, TState5, TState6, TState7>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7>, TOutput>
                        (emptySource, compound, keySelector, GroupInputInliner<TInnerKey, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7>, TOutput>.Transform(reducerTemplate.InlineCalls()));
            }

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate2">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate3">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate4">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate5">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate6">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate7">A concrete reference to an aggregate operator.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        internal static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            IAggregate<TInput, TState1, TOutput1> aggregate1,
            IAggregate<TInput, TState2, TOutput2> aggregate2,
            IAggregate<TInput, TState3, TOutput3> aggregate3,
            IAggregate<TInput, TState4, TOutput4> aggregate4,
            IAggregate<TInput, TState5, TOutput5> aggregate5,
            IAggregate<TInput, TState6, TOutput6> aggregate6,
            IAggregate<TInput, TState7, TOutput7> aggregate7,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7
                };
            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7);

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate2">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate3">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate4">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate5">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate6">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate7">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate8">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        public static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>> aggregate1,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>> aggregate2,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>> aggregate3,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>> aggregate4,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>> aggregate5,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>> aggregate6,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>> aggregate7,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>> aggregate8,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8
                };

            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8);

            if (typeof(TOuterKey) == typeof(Empty) && source.Properties.IsStartEdgeOnly && Config.MapArity == 1)
            {
                var emptySource = (IStreamable<Empty, TInput>)source;
                var emptyAggregate1 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>>)aggregate1;
                var emptyAggregate2 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>>)aggregate2;
                var emptyAggregate3 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>>)aggregate3;
                var emptyAggregate4 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>>)aggregate4;
                var emptyAggregate5 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>>)aggregate5;
                var emptyAggregate6 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>>)aggregate6;
                var emptyAggregate7 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>>)aggregate7;
                var emptyAggregate8 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>>)aggregate8;

                var window = new Window<CompoundGroupKey<Empty, TInnerKey>, TInput>(emptySource.Properties.GroupNested(keySelector));
                var agg1 = emptyAggregate1(window);
                var agg2 = emptyAggregate2(window);
                var agg3 = emptyAggregate3(window);
                var agg4 = emptyAggregate4(window);
                var agg5 = emptyAggregate5(window);
                var agg6 = emptyAggregate6(window);
                var agg7 = emptyAggregate7(window);
                var agg8 = emptyAggregate8(window);
                var compound = AggregateFunctions.Combine(agg1, agg2, agg3, agg4, agg5, agg6, agg7, agg8, aggregateMerger);

                return (IStreamable<TOuterKey, TOutput>)(object)new GroupedWindowStreamable<TInnerKey, TInput, StructTuple<TState1, TState2, TState3, TState4, TState5, TState6, TState7, TState8>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8>, TOutput>
                        (emptySource, compound, keySelector, GroupInputInliner<TInnerKey, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8>, TOutput>.Transform(reducerTemplate.InlineCalls()));
            }

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate2">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate3">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate4">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate5">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate6">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate7">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate8">A concrete reference to an aggregate operator.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        internal static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            IAggregate<TInput, TState1, TOutput1> aggregate1,
            IAggregate<TInput, TState2, TOutput2> aggregate2,
            IAggregate<TInput, TState3, TOutput3> aggregate3,
            IAggregate<TInput, TState4, TOutput4> aggregate4,
            IAggregate<TInput, TState5, TOutput5> aggregate5,
            IAggregate<TInput, TState6, TOutput6> aggregate6,
            IAggregate<TInput, TState7, TOutput7> aggregate7,
            IAggregate<TInput, TState8, TOutput8> aggregate8,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8
                };
            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8);

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TState9">The type of the state object maintained by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput9">The type of the results generated by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate2">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate3">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate4">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate5">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate6">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate7">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate8">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate9">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        public static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TState9, TOutput9, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>> aggregate1,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>> aggregate2,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>> aggregate3,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>> aggregate4,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>> aggregate5,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>> aggregate6,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>> aggregate7,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>> aggregate8,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState9, TOutput9>> aggregate9,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(aggregate9, nameof(aggregate9));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8, output9) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8,
                    Item9 = output9
                };

            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8, outputs.Item9);

            if (typeof(TOuterKey) == typeof(Empty) && source.Properties.IsStartEdgeOnly && Config.MapArity == 1)
            {
                var emptySource = (IStreamable<Empty, TInput>)source;
                var emptyAggregate1 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>>)aggregate1;
                var emptyAggregate2 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>>)aggregate2;
                var emptyAggregate3 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>>)aggregate3;
                var emptyAggregate4 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>>)aggregate4;
                var emptyAggregate5 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>>)aggregate5;
                var emptyAggregate6 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>>)aggregate6;
                var emptyAggregate7 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>>)aggregate7;
                var emptyAggregate8 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>>)aggregate8;
                var emptyAggregate9 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState9, TOutput9>>)aggregate9;

                var window = new Window<CompoundGroupKey<Empty, TInnerKey>, TInput>(emptySource.Properties.GroupNested(keySelector));
                var agg1 = emptyAggregate1(window);
                var agg2 = emptyAggregate2(window);
                var agg3 = emptyAggregate3(window);
                var agg4 = emptyAggregate4(window);
                var agg5 = emptyAggregate5(window);
                var agg6 = emptyAggregate6(window);
                var agg7 = emptyAggregate7(window);
                var agg8 = emptyAggregate8(window);
                var agg9 = emptyAggregate9(window);
                var compound = AggregateFunctions.Combine(agg1, agg2, agg3, agg4, agg5, agg6, agg7, agg8, agg9, aggregateMerger);

                return (IStreamable<TOuterKey, TOutput>)(object)new GroupedWindowStreamable<TInnerKey, TInput, StructTuple<TState1, TState2, TState3, TState4, TState5, TState6, TState7, TState8, TState9>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9>, TOutput>
                        (emptySource, compound, keySelector, GroupInputInliner<TInnerKey, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9>, TOutput>.Transform(reducerTemplate.InlineCalls()));
            }

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregate9, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TState9">The type of the state object maintained by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput9">The type of the results generated by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate2">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate3">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate4">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate5">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate6">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate7">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate8">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate9">A concrete reference to an aggregate operator.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        internal static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TState9, TOutput9, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            IAggregate<TInput, TState1, TOutput1> aggregate1,
            IAggregate<TInput, TState2, TOutput2> aggregate2,
            IAggregate<TInput, TState3, TOutput3> aggregate3,
            IAggregate<TInput, TState4, TOutput4> aggregate4,
            IAggregate<TInput, TState5, TOutput5> aggregate5,
            IAggregate<TInput, TState6, TOutput6> aggregate6,
            IAggregate<TInput, TState7, TOutput7> aggregate7,
            IAggregate<TInput, TState8, TOutput8> aggregate8,
            IAggregate<TInput, TState9, TOutput9> aggregate9,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(aggregate9, nameof(aggregate9));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8, output9) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8,
                    Item9 = output9
                };
            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8, outputs.Item9);

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregate9, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TState9">The type of the state object maintained by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TState10">The type of the state object maintained by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput9">The type of the results generated by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput10">The type of the results generated by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate2">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate3">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate4">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate5">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate6">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate7">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate8">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate9">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate10">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        public static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TState9, TOutput9, TState10, TOutput10, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>> aggregate1,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>> aggregate2,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>> aggregate3,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>> aggregate4,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>> aggregate5,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>> aggregate6,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>> aggregate7,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>> aggregate8,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState9, TOutput9>> aggregate9,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState10, TOutput10>> aggregate10,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(aggregate9, nameof(aggregate9));
            Invariant.IsNotNull(aggregate10, nameof(aggregate10));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8, output9, output10) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8,
                    Item9 = output9,
                    Item10 = output10
                };

            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8, outputs.Item9, outputs.Item10);

            if (typeof(TOuterKey) == typeof(Empty) && source.Properties.IsStartEdgeOnly && Config.MapArity == 1)
            {
                var emptySource = (IStreamable<Empty, TInput>)source;
                var emptyAggregate1 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>>)aggregate1;
                var emptyAggregate2 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>>)aggregate2;
                var emptyAggregate3 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>>)aggregate3;
                var emptyAggregate4 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>>)aggregate4;
                var emptyAggregate5 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>>)aggregate5;
                var emptyAggregate6 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>>)aggregate6;
                var emptyAggregate7 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>>)aggregate7;
                var emptyAggregate8 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>>)aggregate8;
                var emptyAggregate9 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState9, TOutput9>>)aggregate9;
                var emptyAggregate10 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState10, TOutput10>>)aggregate10;

                var window = new Window<CompoundGroupKey<Empty, TInnerKey>, TInput>(emptySource.Properties.GroupNested(keySelector));
                var agg1 = emptyAggregate1(window);
                var agg2 = emptyAggregate2(window);
                var agg3 = emptyAggregate3(window);
                var agg4 = emptyAggregate4(window);
                var agg5 = emptyAggregate5(window);
                var agg6 = emptyAggregate6(window);
                var agg7 = emptyAggregate7(window);
                var agg8 = emptyAggregate8(window);
                var agg9 = emptyAggregate9(window);
                var agg10 = emptyAggregate10(window);
                var compound = AggregateFunctions.Combine(agg1, agg2, agg3, agg4, agg5, agg6, agg7, agg8, agg9, agg10, aggregateMerger);

                return (IStreamable<TOuterKey, TOutput>)(object)new GroupedWindowStreamable<TInnerKey, TInput, StructTuple<TState1, TState2, TState3, TState4, TState5, TState6, TState7, TState8, TState9, TState10>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10>, TOutput>
                        (emptySource, compound, keySelector, GroupInputInliner<TInnerKey, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10>, TOutput>.Transform(reducerTemplate.InlineCalls()));
            }

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregate9, aggregate10, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TState9">The type of the state object maintained by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TState10">The type of the state object maintained by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput9">The type of the results generated by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput10">The type of the results generated by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate2">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate3">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate4">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate5">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate6">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate7">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate8">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate9">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate10">A concrete reference to an aggregate operator.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        internal static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TState9, TOutput9, TState10, TOutput10, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            IAggregate<TInput, TState1, TOutput1> aggregate1,
            IAggregate<TInput, TState2, TOutput2> aggregate2,
            IAggregate<TInput, TState3, TOutput3> aggregate3,
            IAggregate<TInput, TState4, TOutput4> aggregate4,
            IAggregate<TInput, TState5, TOutput5> aggregate5,
            IAggregate<TInput, TState6, TOutput6> aggregate6,
            IAggregate<TInput, TState7, TOutput7> aggregate7,
            IAggregate<TInput, TState8, TOutput8> aggregate8,
            IAggregate<TInput, TState9, TOutput9> aggregate9,
            IAggregate<TInput, TState10, TOutput10> aggregate10,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(aggregate9, nameof(aggregate9));
            Invariant.IsNotNull(aggregate10, nameof(aggregate10));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8, output9, output10) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8,
                    Item9 = output9,
                    Item10 = output10
                };
            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8, outputs.Item9, outputs.Item10);

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregate9, aggregate10, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TState9">The type of the state object maintained by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TState10">The type of the state object maintained by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TState11">The type of the state object maintained by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput9">The type of the results generated by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput10">The type of the results generated by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TOutput11">The type of the results generated by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate2">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate3">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate4">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate5">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate6">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate7">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate8">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate9">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate10">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate11">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        public static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TState9, TOutput9, TState10, TOutput10, TState11, TOutput11, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>> aggregate1,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>> aggregate2,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>> aggregate3,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>> aggregate4,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>> aggregate5,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>> aggregate6,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>> aggregate7,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>> aggregate8,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState9, TOutput9>> aggregate9,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState10, TOutput10>> aggregate10,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState11, TOutput11>> aggregate11,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(aggregate9, nameof(aggregate9));
            Invariant.IsNotNull(aggregate10, nameof(aggregate10));
            Invariant.IsNotNull(aggregate11, nameof(aggregate11));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8, output9, output10, output11) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8,
                    Item9 = output9,
                    Item10 = output10,
                    Item11 = output11
                };

            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8, outputs.Item9, outputs.Item10, outputs.Item11);

            if (typeof(TOuterKey) == typeof(Empty) && source.Properties.IsStartEdgeOnly && Config.MapArity == 1)
            {
                var emptySource = (IStreamable<Empty, TInput>)source;
                var emptyAggregate1 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>>)aggregate1;
                var emptyAggregate2 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>>)aggregate2;
                var emptyAggregate3 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>>)aggregate3;
                var emptyAggregate4 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>>)aggregate4;
                var emptyAggregate5 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>>)aggregate5;
                var emptyAggregate6 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>>)aggregate6;
                var emptyAggregate7 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>>)aggregate7;
                var emptyAggregate8 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>>)aggregate8;
                var emptyAggregate9 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState9, TOutput9>>)aggregate9;
                var emptyAggregate10 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState10, TOutput10>>)aggregate10;
                var emptyAggregate11 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState11, TOutput11>>)aggregate11;

                var window = new Window<CompoundGroupKey<Empty, TInnerKey>, TInput>(emptySource.Properties.GroupNested(keySelector));
                var agg1 = emptyAggregate1(window);
                var agg2 = emptyAggregate2(window);
                var agg3 = emptyAggregate3(window);
                var agg4 = emptyAggregate4(window);
                var agg5 = emptyAggregate5(window);
                var agg6 = emptyAggregate6(window);
                var agg7 = emptyAggregate7(window);
                var agg8 = emptyAggregate8(window);
                var agg9 = emptyAggregate9(window);
                var agg10 = emptyAggregate10(window);
                var agg11 = emptyAggregate11(window);
                var compound = AggregateFunctions.Combine(agg1, agg2, agg3, agg4, agg5, agg6, agg7, agg8, agg9, agg10, agg11, aggregateMerger);

                return (IStreamable<TOuterKey, TOutput>)(object)new GroupedWindowStreamable<TInnerKey, TInput, StructTuple<TState1, TState2, TState3, TState4, TState5, TState6, TState7, TState8, TState9, TState10, TState11>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11>, TOutput>
                        (emptySource, compound, keySelector, GroupInputInliner<TInnerKey, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11>, TOutput>.Transform(reducerTemplate.InlineCalls()));
            }

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregate9, aggregate10, aggregate11, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TState9">The type of the state object maintained by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TState10">The type of the state object maintained by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TState11">The type of the state object maintained by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput9">The type of the results generated by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput10">The type of the results generated by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TOutput11">The type of the results generated by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate2">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate3">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate4">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate5">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate6">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate7">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate8">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate9">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate10">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate11">A concrete reference to an aggregate operator.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        internal static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TState9, TOutput9, TState10, TOutput10, TState11, TOutput11, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            IAggregate<TInput, TState1, TOutput1> aggregate1,
            IAggregate<TInput, TState2, TOutput2> aggregate2,
            IAggregate<TInput, TState3, TOutput3> aggregate3,
            IAggregate<TInput, TState4, TOutput4> aggregate4,
            IAggregate<TInput, TState5, TOutput5> aggregate5,
            IAggregate<TInput, TState6, TOutput6> aggregate6,
            IAggregate<TInput, TState7, TOutput7> aggregate7,
            IAggregate<TInput, TState8, TOutput8> aggregate8,
            IAggregate<TInput, TState9, TOutput9> aggregate9,
            IAggregate<TInput, TState10, TOutput10> aggregate10,
            IAggregate<TInput, TState11, TOutput11> aggregate11,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(aggregate9, nameof(aggregate9));
            Invariant.IsNotNull(aggregate10, nameof(aggregate10));
            Invariant.IsNotNull(aggregate11, nameof(aggregate11));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8, output9, output10, output11) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8,
                    Item9 = output9,
                    Item10 = output10,
                    Item11 = output11
                };
            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8, outputs.Item9, outputs.Item10, outputs.Item11);

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregate9, aggregate10, aggregate11, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TState9">The type of the state object maintained by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TState10">The type of the state object maintained by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TState11">The type of the state object maintained by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TState12">The type of the state object maintained by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput9">The type of the results generated by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput10">The type of the results generated by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TOutput11">The type of the results generated by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TOutput12">The type of the results generated by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate2">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate3">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate4">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate5">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate6">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate7">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate8">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate9">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate10">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate11">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate12">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        public static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TState9, TOutput9, TState10, TOutput10, TState11, TOutput11, TState12, TOutput12, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>> aggregate1,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>> aggregate2,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>> aggregate3,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>> aggregate4,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>> aggregate5,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>> aggregate6,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>> aggregate7,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>> aggregate8,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState9, TOutput9>> aggregate9,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState10, TOutput10>> aggregate10,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState11, TOutput11>> aggregate11,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState12, TOutput12>> aggregate12,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(aggregate9, nameof(aggregate9));
            Invariant.IsNotNull(aggregate10, nameof(aggregate10));
            Invariant.IsNotNull(aggregate11, nameof(aggregate11));
            Invariant.IsNotNull(aggregate12, nameof(aggregate12));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8, output9, output10, output11, output12) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8,
                    Item9 = output9,
                    Item10 = output10,
                    Item11 = output11,
                    Item12 = output12
                };

            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8, outputs.Item9, outputs.Item10, outputs.Item11, outputs.Item12);

            if (typeof(TOuterKey) == typeof(Empty) && source.Properties.IsStartEdgeOnly && Config.MapArity == 1)
            {
                var emptySource = (IStreamable<Empty, TInput>)source;
                var emptyAggregate1 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>>)aggregate1;
                var emptyAggregate2 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>>)aggregate2;
                var emptyAggregate3 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>>)aggregate3;
                var emptyAggregate4 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>>)aggregate4;
                var emptyAggregate5 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>>)aggregate5;
                var emptyAggregate6 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>>)aggregate6;
                var emptyAggregate7 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>>)aggregate7;
                var emptyAggregate8 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>>)aggregate8;
                var emptyAggregate9 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState9, TOutput9>>)aggregate9;
                var emptyAggregate10 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState10, TOutput10>>)aggregate10;
                var emptyAggregate11 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState11, TOutput11>>)aggregate11;
                var emptyAggregate12 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState12, TOutput12>>)aggregate12;

                var window = new Window<CompoundGroupKey<Empty, TInnerKey>, TInput>(emptySource.Properties.GroupNested(keySelector));
                var agg1 = emptyAggregate1(window);
                var agg2 = emptyAggregate2(window);
                var agg3 = emptyAggregate3(window);
                var agg4 = emptyAggregate4(window);
                var agg5 = emptyAggregate5(window);
                var agg6 = emptyAggregate6(window);
                var agg7 = emptyAggregate7(window);
                var agg8 = emptyAggregate8(window);
                var agg9 = emptyAggregate9(window);
                var agg10 = emptyAggregate10(window);
                var agg11 = emptyAggregate11(window);
                var agg12 = emptyAggregate12(window);
                var compound = AggregateFunctions.Combine(agg1, agg2, agg3, agg4, agg5, agg6, agg7, agg8, agg9, agg10, agg11, agg12, aggregateMerger);

                return (IStreamable<TOuterKey, TOutput>)(object)new GroupedWindowStreamable<TInnerKey, TInput, StructTuple<TState1, TState2, TState3, TState4, TState5, TState6, TState7, TState8, TState9, TState10, TState11, TState12>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12>, TOutput>
                        (emptySource, compound, keySelector, GroupInputInliner<TInnerKey, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12>, TOutput>.Transform(reducerTemplate.InlineCalls()));
            }

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregate9, aggregate10, aggregate11, aggregate12, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TState9">The type of the state object maintained by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TState10">The type of the state object maintained by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TState11">The type of the state object maintained by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TState12">The type of the state object maintained by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput9">The type of the results generated by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput10">The type of the results generated by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TOutput11">The type of the results generated by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TOutput12">The type of the results generated by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate2">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate3">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate4">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate5">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate6">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate7">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate8">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate9">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate10">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate11">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate12">A concrete reference to an aggregate operator.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        internal static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TState9, TOutput9, TState10, TOutput10, TState11, TOutput11, TState12, TOutput12, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            IAggregate<TInput, TState1, TOutput1> aggregate1,
            IAggregate<TInput, TState2, TOutput2> aggregate2,
            IAggregate<TInput, TState3, TOutput3> aggregate3,
            IAggregate<TInput, TState4, TOutput4> aggregate4,
            IAggregate<TInput, TState5, TOutput5> aggregate5,
            IAggregate<TInput, TState6, TOutput6> aggregate6,
            IAggregate<TInput, TState7, TOutput7> aggregate7,
            IAggregate<TInput, TState8, TOutput8> aggregate8,
            IAggregate<TInput, TState9, TOutput9> aggregate9,
            IAggregate<TInput, TState10, TOutput10> aggregate10,
            IAggregate<TInput, TState11, TOutput11> aggregate11,
            IAggregate<TInput, TState12, TOutput12> aggregate12,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(aggregate9, nameof(aggregate9));
            Invariant.IsNotNull(aggregate10, nameof(aggregate10));
            Invariant.IsNotNull(aggregate11, nameof(aggregate11));
            Invariant.IsNotNull(aggregate12, nameof(aggregate12));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8, output9, output10, output11, output12) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8,
                    Item9 = output9,
                    Item10 = output10,
                    Item11 = output11,
                    Item12 = output12
                };
            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8, outputs.Item9, outputs.Item10, outputs.Item11, outputs.Item12);

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregate9, aggregate10, aggregate11, aggregate12, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TState9">The type of the state object maintained by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TState10">The type of the state object maintained by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TState11">The type of the state object maintained by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TState12">The type of the state object maintained by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TState13">The type of the state object maintained by the aggregate operation in position 13.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput9">The type of the results generated by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput10">The type of the results generated by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TOutput11">The type of the results generated by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TOutput12">The type of the results generated by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TOutput13">The type of the results generated by the aggregate operation in position 13.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate2">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate3">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate4">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate5">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate6">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate7">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate8">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate9">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate10">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate11">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate12">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate13">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        public static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TState9, TOutput9, TState10, TOutput10, TState11, TOutput11, TState12, TOutput12, TState13, TOutput13, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>> aggregate1,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>> aggregate2,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>> aggregate3,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>> aggregate4,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>> aggregate5,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>> aggregate6,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>> aggregate7,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>> aggregate8,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState9, TOutput9>> aggregate9,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState10, TOutput10>> aggregate10,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState11, TOutput11>> aggregate11,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState12, TOutput12>> aggregate12,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState13, TOutput13>> aggregate13,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(aggregate9, nameof(aggregate9));
            Invariant.IsNotNull(aggregate10, nameof(aggregate10));
            Invariant.IsNotNull(aggregate11, nameof(aggregate11));
            Invariant.IsNotNull(aggregate12, nameof(aggregate12));
            Invariant.IsNotNull(aggregate13, nameof(aggregate13));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8, output9, output10, output11, output12, output13) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8,
                    Item9 = output9,
                    Item10 = output10,
                    Item11 = output11,
                    Item12 = output12,
                    Item13 = output13
                };

            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8, outputs.Item9, outputs.Item10, outputs.Item11, outputs.Item12, outputs.Item13);

            if (typeof(TOuterKey) == typeof(Empty) && source.Properties.IsStartEdgeOnly && Config.MapArity == 1)
            {
                var emptySource = (IStreamable<Empty, TInput>)source;
                var emptyAggregate1 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>>)aggregate1;
                var emptyAggregate2 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>>)aggregate2;
                var emptyAggregate3 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>>)aggregate3;
                var emptyAggregate4 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>>)aggregate4;
                var emptyAggregate5 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>>)aggregate5;
                var emptyAggregate6 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>>)aggregate6;
                var emptyAggregate7 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>>)aggregate7;
                var emptyAggregate8 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>>)aggregate8;
                var emptyAggregate9 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState9, TOutput9>>)aggregate9;
                var emptyAggregate10 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState10, TOutput10>>)aggregate10;
                var emptyAggregate11 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState11, TOutput11>>)aggregate11;
                var emptyAggregate12 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState12, TOutput12>>)aggregate12;
                var emptyAggregate13 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState13, TOutput13>>)aggregate13;

                var window = new Window<CompoundGroupKey<Empty, TInnerKey>, TInput>(emptySource.Properties.GroupNested(keySelector));
                var agg1 = emptyAggregate1(window);
                var agg2 = emptyAggregate2(window);
                var agg3 = emptyAggregate3(window);
                var agg4 = emptyAggregate4(window);
                var agg5 = emptyAggregate5(window);
                var agg6 = emptyAggregate6(window);
                var agg7 = emptyAggregate7(window);
                var agg8 = emptyAggregate8(window);
                var agg9 = emptyAggregate9(window);
                var agg10 = emptyAggregate10(window);
                var agg11 = emptyAggregate11(window);
                var agg12 = emptyAggregate12(window);
                var agg13 = emptyAggregate13(window);
                var compound = AggregateFunctions.Combine(agg1, agg2, agg3, agg4, agg5, agg6, agg7, agg8, agg9, agg10, agg11, agg12, agg13, aggregateMerger);

                return (IStreamable<TOuterKey, TOutput>)(object)new GroupedWindowStreamable<TInnerKey, TInput, StructTuple<TState1, TState2, TState3, TState4, TState5, TState6, TState7, TState8, TState9, TState10, TState11, TState12, TState13>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13>, TOutput>
                        (emptySource, compound, keySelector, GroupInputInliner<TInnerKey, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13>, TOutput>.Transform(reducerTemplate.InlineCalls()));
            }

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregate9, aggregate10, aggregate11, aggregate12, aggregate13, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TState9">The type of the state object maintained by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TState10">The type of the state object maintained by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TState11">The type of the state object maintained by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TState12">The type of the state object maintained by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TState13">The type of the state object maintained by the aggregate operation in position 13.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput9">The type of the results generated by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput10">The type of the results generated by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TOutput11">The type of the results generated by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TOutput12">The type of the results generated by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TOutput13">The type of the results generated by the aggregate operation in position 13.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate2">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate3">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate4">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate5">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate6">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate7">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate8">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate9">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate10">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate11">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate12">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate13">A concrete reference to an aggregate operator.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        internal static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TState9, TOutput9, TState10, TOutput10, TState11, TOutput11, TState12, TOutput12, TState13, TOutput13, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            IAggregate<TInput, TState1, TOutput1> aggregate1,
            IAggregate<TInput, TState2, TOutput2> aggregate2,
            IAggregate<TInput, TState3, TOutput3> aggregate3,
            IAggregate<TInput, TState4, TOutput4> aggregate4,
            IAggregate<TInput, TState5, TOutput5> aggregate5,
            IAggregate<TInput, TState6, TOutput6> aggregate6,
            IAggregate<TInput, TState7, TOutput7> aggregate7,
            IAggregate<TInput, TState8, TOutput8> aggregate8,
            IAggregate<TInput, TState9, TOutput9> aggregate9,
            IAggregate<TInput, TState10, TOutput10> aggregate10,
            IAggregate<TInput, TState11, TOutput11> aggregate11,
            IAggregate<TInput, TState12, TOutput12> aggregate12,
            IAggregate<TInput, TState13, TOutput13> aggregate13,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(aggregate9, nameof(aggregate9));
            Invariant.IsNotNull(aggregate10, nameof(aggregate10));
            Invariant.IsNotNull(aggregate11, nameof(aggregate11));
            Invariant.IsNotNull(aggregate12, nameof(aggregate12));
            Invariant.IsNotNull(aggregate13, nameof(aggregate13));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8, output9, output10, output11, output12, output13) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8,
                    Item9 = output9,
                    Item10 = output10,
                    Item11 = output11,
                    Item12 = output12,
                    Item13 = output13
                };
            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8, outputs.Item9, outputs.Item10, outputs.Item11, outputs.Item12, outputs.Item13);

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregate9, aggregate10, aggregate11, aggregate12, aggregate13, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TState9">The type of the state object maintained by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TState10">The type of the state object maintained by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TState11">The type of the state object maintained by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TState12">The type of the state object maintained by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TState13">The type of the state object maintained by the aggregate operation in position 13.</typeparam>
        /// <typeparam name="TState14">The type of the state object maintained by the aggregate operation in position 14.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput9">The type of the results generated by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput10">The type of the results generated by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TOutput11">The type of the results generated by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TOutput12">The type of the results generated by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TOutput13">The type of the results generated by the aggregate operation in position 13.</typeparam>
        /// <typeparam name="TOutput14">The type of the results generated by the aggregate operation in position 14.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate2">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate3">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate4">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate5">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate6">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate7">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate8">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate9">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate10">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate11">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate12">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate13">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate14">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        public static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TState9, TOutput9, TState10, TOutput10, TState11, TOutput11, TState12, TOutput12, TState13, TOutput13, TState14, TOutput14, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>> aggregate1,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>> aggregate2,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>> aggregate3,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>> aggregate4,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>> aggregate5,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>> aggregate6,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>> aggregate7,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>> aggregate8,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState9, TOutput9>> aggregate9,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState10, TOutput10>> aggregate10,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState11, TOutput11>> aggregate11,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState12, TOutput12>> aggregate12,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState13, TOutput13>> aggregate13,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState14, TOutput14>> aggregate14,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(aggregate9, nameof(aggregate9));
            Invariant.IsNotNull(aggregate10, nameof(aggregate10));
            Invariant.IsNotNull(aggregate11, nameof(aggregate11));
            Invariant.IsNotNull(aggregate12, nameof(aggregate12));
            Invariant.IsNotNull(aggregate13, nameof(aggregate13));
            Invariant.IsNotNull(aggregate14, nameof(aggregate14));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8, output9, output10, output11, output12, output13, output14) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8,
                    Item9 = output9,
                    Item10 = output10,
                    Item11 = output11,
                    Item12 = output12,
                    Item13 = output13,
                    Item14 = output14
                };

            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8, outputs.Item9, outputs.Item10, outputs.Item11, outputs.Item12, outputs.Item13, outputs.Item14);

            if (typeof(TOuterKey) == typeof(Empty) && source.Properties.IsStartEdgeOnly && Config.MapArity == 1)
            {
                var emptySource = (IStreamable<Empty, TInput>)source;
                var emptyAggregate1 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>>)aggregate1;
                var emptyAggregate2 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>>)aggregate2;
                var emptyAggregate3 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>>)aggregate3;
                var emptyAggregate4 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>>)aggregate4;
                var emptyAggregate5 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>>)aggregate5;
                var emptyAggregate6 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>>)aggregate6;
                var emptyAggregate7 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>>)aggregate7;
                var emptyAggregate8 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>>)aggregate8;
                var emptyAggregate9 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState9, TOutput9>>)aggregate9;
                var emptyAggregate10 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState10, TOutput10>>)aggregate10;
                var emptyAggregate11 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState11, TOutput11>>)aggregate11;
                var emptyAggregate12 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState12, TOutput12>>)aggregate12;
                var emptyAggregate13 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState13, TOutput13>>)aggregate13;
                var emptyAggregate14 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState14, TOutput14>>)aggregate14;

                var window = new Window<CompoundGroupKey<Empty, TInnerKey>, TInput>(emptySource.Properties.GroupNested(keySelector));
                var agg1 = emptyAggregate1(window);
                var agg2 = emptyAggregate2(window);
                var agg3 = emptyAggregate3(window);
                var agg4 = emptyAggregate4(window);
                var agg5 = emptyAggregate5(window);
                var agg6 = emptyAggregate6(window);
                var agg7 = emptyAggregate7(window);
                var agg8 = emptyAggregate8(window);
                var agg9 = emptyAggregate9(window);
                var agg10 = emptyAggregate10(window);
                var agg11 = emptyAggregate11(window);
                var agg12 = emptyAggregate12(window);
                var agg13 = emptyAggregate13(window);
                var agg14 = emptyAggregate14(window);
                var compound = AggregateFunctions.Combine(agg1, agg2, agg3, agg4, agg5, agg6, agg7, agg8, agg9, agg10, agg11, agg12, agg13, agg14, aggregateMerger);

                return (IStreamable<TOuterKey, TOutput>)(object)new GroupedWindowStreamable<TInnerKey, TInput, StructTuple<TState1, TState2, TState3, TState4, TState5, TState6, TState7, TState8, TState9, TState10, TState11, TState12, TState13, TState14>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14>, TOutput>
                        (emptySource, compound, keySelector, GroupInputInliner<TInnerKey, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14>, TOutput>.Transform(reducerTemplate.InlineCalls()));
            }

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregate9, aggregate10, aggregate11, aggregate12, aggregate13, aggregate14, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TState9">The type of the state object maintained by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TState10">The type of the state object maintained by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TState11">The type of the state object maintained by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TState12">The type of the state object maintained by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TState13">The type of the state object maintained by the aggregate operation in position 13.</typeparam>
        /// <typeparam name="TState14">The type of the state object maintained by the aggregate operation in position 14.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput9">The type of the results generated by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput10">The type of the results generated by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TOutput11">The type of the results generated by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TOutput12">The type of the results generated by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TOutput13">The type of the results generated by the aggregate operation in position 13.</typeparam>
        /// <typeparam name="TOutput14">The type of the results generated by the aggregate operation in position 14.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate2">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate3">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate4">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate5">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate6">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate7">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate8">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate9">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate10">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate11">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate12">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate13">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate14">A concrete reference to an aggregate operator.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        internal static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TState9, TOutput9, TState10, TOutput10, TState11, TOutput11, TState12, TOutput12, TState13, TOutput13, TState14, TOutput14, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            IAggregate<TInput, TState1, TOutput1> aggregate1,
            IAggregate<TInput, TState2, TOutput2> aggregate2,
            IAggregate<TInput, TState3, TOutput3> aggregate3,
            IAggregate<TInput, TState4, TOutput4> aggregate4,
            IAggregate<TInput, TState5, TOutput5> aggregate5,
            IAggregate<TInput, TState6, TOutput6> aggregate6,
            IAggregate<TInput, TState7, TOutput7> aggregate7,
            IAggregate<TInput, TState8, TOutput8> aggregate8,
            IAggregate<TInput, TState9, TOutput9> aggregate9,
            IAggregate<TInput, TState10, TOutput10> aggregate10,
            IAggregate<TInput, TState11, TOutput11> aggregate11,
            IAggregate<TInput, TState12, TOutput12> aggregate12,
            IAggregate<TInput, TState13, TOutput13> aggregate13,
            IAggregate<TInput, TState14, TOutput14> aggregate14,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(aggregate9, nameof(aggregate9));
            Invariant.IsNotNull(aggregate10, nameof(aggregate10));
            Invariant.IsNotNull(aggregate11, nameof(aggregate11));
            Invariant.IsNotNull(aggregate12, nameof(aggregate12));
            Invariant.IsNotNull(aggregate13, nameof(aggregate13));
            Invariant.IsNotNull(aggregate14, nameof(aggregate14));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8, output9, output10, output11, output12, output13, output14) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8,
                    Item9 = output9,
                    Item10 = output10,
                    Item11 = output11,
                    Item12 = output12,
                    Item13 = output13,
                    Item14 = output14
                };
            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8, outputs.Item9, outputs.Item10, outputs.Item11, outputs.Item12, outputs.Item13, outputs.Item14);

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregate9, aggregate10, aggregate11, aggregate12, aggregate13, aggregate14, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TState9">The type of the state object maintained by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TState10">The type of the state object maintained by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TState11">The type of the state object maintained by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TState12">The type of the state object maintained by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TState13">The type of the state object maintained by the aggregate operation in position 13.</typeparam>
        /// <typeparam name="TState14">The type of the state object maintained by the aggregate operation in position 14.</typeparam>
        /// <typeparam name="TState15">The type of the state object maintained by the aggregate operation in position 15.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput9">The type of the results generated by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput10">The type of the results generated by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TOutput11">The type of the results generated by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TOutput12">The type of the results generated by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TOutput13">The type of the results generated by the aggregate operation in position 13.</typeparam>
        /// <typeparam name="TOutput14">The type of the results generated by the aggregate operation in position 14.</typeparam>
        /// <typeparam name="TOutput15">The type of the results generated by the aggregate operation in position 15.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate2">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate3">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate4">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate5">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate6">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate7">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate8">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate9">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate10">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate11">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate12">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate13">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate14">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="aggregate15">A function from a window to an aggregate object. Used to give the developer an autocomplete experience in Visual Studio to pick from a set of available aggregates.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        public static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TState9, TOutput9, TState10, TOutput10, TState11, TOutput11, TState12, TOutput12, TState13, TOutput13, TState14, TOutput14, TState15, TOutput15, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>> aggregate1,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>> aggregate2,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>> aggregate3,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>> aggregate4,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>> aggregate5,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>> aggregate6,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>> aggregate7,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>> aggregate8,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState9, TOutput9>> aggregate9,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState10, TOutput10>> aggregate10,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState11, TOutput11>> aggregate11,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState12, TOutput12>> aggregate12,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState13, TOutput13>> aggregate13,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState14, TOutput14>> aggregate14,
            Func<Window<CompoundGroupKey<TOuterKey, TInnerKey>, TInput>, IAggregate<TInput, TState15, TOutput15>> aggregate15,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, TOutput15, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(aggregate9, nameof(aggregate9));
            Invariant.IsNotNull(aggregate10, nameof(aggregate10));
            Invariant.IsNotNull(aggregate11, nameof(aggregate11));
            Invariant.IsNotNull(aggregate12, nameof(aggregate12));
            Invariant.IsNotNull(aggregate13, nameof(aggregate13));
            Invariant.IsNotNull(aggregate14, nameof(aggregate14));
            Invariant.IsNotNull(aggregate15, nameof(aggregate15));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, TOutput15, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, TOutput15>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8, output9, output10, output11, output12, output13, output14, output15) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, TOutput15> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8,
                    Item9 = output9,
                    Item10 = output10,
                    Item11 = output11,
                    Item12 = output12,
                    Item13 = output13,
                    Item14 = output14,
                    Item15 = output15
                };

            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, TOutput15>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8, outputs.Item9, outputs.Item10, outputs.Item11, outputs.Item12, outputs.Item13, outputs.Item14, outputs.Item15);

            if (typeof(TOuterKey) == typeof(Empty) && source.Properties.IsStartEdgeOnly && Config.MapArity == 1)
            {
                var emptySource = (IStreamable<Empty, TInput>)source;
                var emptyAggregate1 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState1, TOutput1>>)aggregate1;
                var emptyAggregate2 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState2, TOutput2>>)aggregate2;
                var emptyAggregate3 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState3, TOutput3>>)aggregate3;
                var emptyAggregate4 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState4, TOutput4>>)aggregate4;
                var emptyAggregate5 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState5, TOutput5>>)aggregate5;
                var emptyAggregate6 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState6, TOutput6>>)aggregate6;
                var emptyAggregate7 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState7, TOutput7>>)aggregate7;
                var emptyAggregate8 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState8, TOutput8>>)aggregate8;
                var emptyAggregate9 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState9, TOutput9>>)aggregate9;
                var emptyAggregate10 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState10, TOutput10>>)aggregate10;
                var emptyAggregate11 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState11, TOutput11>>)aggregate11;
                var emptyAggregate12 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState12, TOutput12>>)aggregate12;
                var emptyAggregate13 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState13, TOutput13>>)aggregate13;
                var emptyAggregate14 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState14, TOutput14>>)aggregate14;
                var emptyAggregate15 = (Func<Window<CompoundGroupKey<Empty, TInnerKey>, TInput>, IAggregate<TInput, TState15, TOutput15>>)aggregate15;

                var window = new Window<CompoundGroupKey<Empty, TInnerKey>, TInput>(emptySource.Properties.GroupNested(keySelector));
                var agg1 = emptyAggregate1(window);
                var agg2 = emptyAggregate2(window);
                var agg3 = emptyAggregate3(window);
                var agg4 = emptyAggregate4(window);
                var agg5 = emptyAggregate5(window);
                var agg6 = emptyAggregate6(window);
                var agg7 = emptyAggregate7(window);
                var agg8 = emptyAggregate8(window);
                var agg9 = emptyAggregate9(window);
                var agg10 = emptyAggregate10(window);
                var agg11 = emptyAggregate11(window);
                var agg12 = emptyAggregate12(window);
                var agg13 = emptyAggregate13(window);
                var agg14 = emptyAggregate14(window);
                var agg15 = emptyAggregate15(window);
                var compound = AggregateFunctions.Combine(agg1, agg2, agg3, agg4, agg5, agg6, agg7, agg8, agg9, agg10, agg11, agg12, agg13, agg14, agg15, aggregateMerger);

                return (IStreamable<TOuterKey, TOutput>)(object)new GroupedWindowStreamable<TInnerKey, TInput, StructTuple<TState1, TState2, TState3, TState4, TState5, TState6, TState7, TState8, TState9, TState10, TState11, TState12, TState13, TState14, TState15>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, TOutput15>, TOutput>
                        (emptySource, compound, keySelector, GroupInputInliner<TInnerKey, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, TOutput15>, TOutput>.Transform(reducerTemplate.InlineCalls()));
            }

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregate9, aggregate10, aggregate11, aggregate12, aggregate13, aggregate14, aggregate15, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }

        /// <summary>
        /// Groups input events by a key selector and applies multiple aggregates on each group.
        /// </summary>
        /// <typeparam name="TOuterKey">The type of the grouping key of the stream coming into the aggregation operation.</typeparam>
        /// <typeparam name="TInput">The type of the payload in the input stream.</typeparam>
        /// <typeparam name="TInnerKey">The result type of the expression used to group data in the aggregation.</typeparam>
        /// <typeparam name="TState1">The type of the state object maintained by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TState2">The type of the state object maintained by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TState3">The type of the state object maintained by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TState4">The type of the state object maintained by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TState5">The type of the state object maintained by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TState6">The type of the state object maintained by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TState7">The type of the state object maintained by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TState8">The type of the state object maintained by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TState9">The type of the state object maintained by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TState10">The type of the state object maintained by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TState11">The type of the state object maintained by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TState12">The type of the state object maintained by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TState13">The type of the state object maintained by the aggregate operation in position 13.</typeparam>
        /// <typeparam name="TState14">The type of the state object maintained by the aggregate operation in position 14.</typeparam>
        /// <typeparam name="TState15">The type of the state object maintained by the aggregate operation in position 15.</typeparam>
        /// <typeparam name="TOutput1">The type of the results generated by the aggregate operation in position 1.</typeparam>
        /// <typeparam name="TOutput2">The type of the results generated by the aggregate operation in position 2.</typeparam>
        /// <typeparam name="TOutput3">The type of the results generated by the aggregate operation in position 3.</typeparam>
        /// <typeparam name="TOutput4">The type of the results generated by the aggregate operation in position 4.</typeparam>
        /// <typeparam name="TOutput5">The type of the results generated by the aggregate operation in position 5.</typeparam>
        /// <typeparam name="TOutput6">The type of the results generated by the aggregate operation in position 6.</typeparam>
        /// <typeparam name="TOutput7">The type of the results generated by the aggregate operation in position 7.</typeparam>
        /// <typeparam name="TOutput8">The type of the results generated by the aggregate operation in position 8.</typeparam>
        /// <typeparam name="TOutput9">The type of the results generated by the aggregate operation in position 9.</typeparam>
        /// <typeparam name="TOutput10">The type of the results generated by the aggregate operation in position 10.</typeparam>
        /// <typeparam name="TOutput11">The type of the results generated by the aggregate operation in position 11.</typeparam>
        /// <typeparam name="TOutput12">The type of the results generated by the aggregate operation in position 12.</typeparam>
        /// <typeparam name="TOutput13">The type of the results generated by the aggregate operation in position 13.</typeparam>
        /// <typeparam name="TOutput14">The type of the results generated by the aggregate operation in position 14.</typeparam>
        /// <typeparam name="TOutput15">The type of the results generated by the aggregate operation in position 15.</typeparam>
        /// <typeparam name="TOutput">The type of the payloads of the resulting stream.</typeparam>
        /// <param name="source">The stream over which to aggregate data.</param>
        /// <param name="keySelector">An expression describing how to group data for use in the aggregate expression.</param>
        /// <param name="aggregate1">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate2">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate3">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate4">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate5">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate6">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate7">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate8">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate9">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate10">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate11">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate12">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate13">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate14">A concrete reference to an aggregate operator.</param>
        /// <param name="aggregate15">A concrete reference to an aggregate operator.</param>
        /// <param name="merger">An expression describing how to merge the grouping key and the result of the aggregation into a result payload.</param>
        /// <returns>A stream of grouping key type <typeparamref name="TOuterKey"/> and result payload type <typeparamref name="TOutput"/>.</returns>
        internal static IStreamable<TOuterKey, TOutput> GroupAggregate<TOuterKey, TInput, TInnerKey, TState1, TOutput1, TState2, TOutput2, TState3, TOutput3, TState4, TOutput4, TState5, TOutput5, TState6, TOutput6, TState7, TOutput7, TState8, TOutput8, TState9, TOutput9, TState10, TOutput10, TState11, TOutput11, TState12, TOutput12, TState13, TOutput13, TState14, TOutput14, TState15, TOutput15, TOutput>(
            this IStreamable<TOuterKey, TInput> source,
            Expression<Func<TInput, TInnerKey>> keySelector,
            IAggregate<TInput, TState1, TOutput1> aggregate1,
            IAggregate<TInput, TState2, TOutput2> aggregate2,
            IAggregate<TInput, TState3, TOutput3> aggregate3,
            IAggregate<TInput, TState4, TOutput4> aggregate4,
            IAggregate<TInput, TState5, TOutput5> aggregate5,
            IAggregate<TInput, TState6, TOutput6> aggregate6,
            IAggregate<TInput, TState7, TOutput7> aggregate7,
            IAggregate<TInput, TState8, TOutput8> aggregate8,
            IAggregate<TInput, TState9, TOutput9> aggregate9,
            IAggregate<TInput, TState10, TOutput10> aggregate10,
            IAggregate<TInput, TState11, TOutput11> aggregate11,
            IAggregate<TInput, TState12, TOutput12> aggregate12,
            IAggregate<TInput, TState13, TOutput13> aggregate13,
            IAggregate<TInput, TState14, TOutput14> aggregate14,
            IAggregate<TInput, TState15, TOutput15> aggregate15,
            Expression<Func<GroupSelectorInput<TInnerKey>, TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, TOutput15, TOutput>> merger)
        {
            Invariant.IsNotNull(source, nameof(source));
            Invariant.IsNotNull(keySelector, nameof(keySelector));
            Invariant.IsNotNull(aggregate1, nameof(aggregate1));
            Invariant.IsNotNull(aggregate2, nameof(aggregate2));
            Invariant.IsNotNull(aggregate3, nameof(aggregate3));
            Invariant.IsNotNull(aggregate4, nameof(aggregate4));
            Invariant.IsNotNull(aggregate5, nameof(aggregate5));
            Invariant.IsNotNull(aggregate6, nameof(aggregate6));
            Invariant.IsNotNull(aggregate7, nameof(aggregate7));
            Invariant.IsNotNull(aggregate8, nameof(aggregate8));
            Invariant.IsNotNull(aggregate9, nameof(aggregate9));
            Invariant.IsNotNull(aggregate10, nameof(aggregate10));
            Invariant.IsNotNull(aggregate11, nameof(aggregate11));
            Invariant.IsNotNull(aggregate12, nameof(aggregate12));
            Invariant.IsNotNull(aggregate13, nameof(aggregate13));
            Invariant.IsNotNull(aggregate14, nameof(aggregate14));
            Invariant.IsNotNull(aggregate15, nameof(aggregate15));
            Invariant.IsNotNull(merger, nameof(merger));

            Expression<Func<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, TOutput15, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, TOutput15>>> aggregateMerger =
                (output1, output2, output3, output4, output5, output6, output7, output8, output9, output10, output11, output12, output13, output14, output15) => new StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, TOutput15> {
                    Item1 = output1,
                    Item2 = output2,
                    Item3 = output3,
                    Item4 = output4,
                    Item5 = output5,
                    Item6 = output6,
                    Item7 = output7,
                    Item8 = output8,
                    Item9 = output9,
                    Item10 = output10,
                    Item11 = output11,
                    Item12 = output12,
                    Item13 = output13,
                    Item14 = output14,
                    Item15 = output15
                };
            Expression<Func<GroupSelectorInput<TInnerKey>, StructTuple<TOutput1, TOutput2, TOutput3, TOutput4, TOutput5, TOutput6, TOutput7, TOutput8, TOutput9, TOutput10, TOutput11, TOutput12, TOutput13, TOutput14, TOutput15>, TOutput>> reducerTemplate =
                (key, outputs) => CallInliner.Call(merger, key, outputs.Item1, outputs.Item2, outputs.Item3, outputs.Item4, outputs.Item5, outputs.Item6, outputs.Item7, outputs.Item8, outputs.Item9, outputs.Item10, outputs.Item11, outputs.Item12, outputs.Item13, outputs.Item14, outputs.Item15);

            return source.Map(keySelector)
                         .Reduce(
                             s => s.Aggregate(aggregate1, aggregate2, aggregate3, aggregate4, aggregate5, aggregate6, aggregate7, aggregate8, aggregate9, aggregate10, aggregate11, aggregate12, aggregate13, aggregate14, aggregate15, aggregateMerger),
                             reducerTemplate.InlineCalls());
        }
    }
}